home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / langs / iconv8_l.arc / IDOL.ARC / IDOL.DOC < prev    next >
Encoding:
Text File  |  1990-03-19  |  49.5 KB  |  1,234 lines

  1.  
  2.  
  3.  
  4.                 Programming in Idol: An Object Primer
  5.  
  6.                           Clinton L. Jeffery
  7.  
  8.                            March 14, 1990
  9.  
  10. Idol is an object-oriented extension and environment for the
  11. Icon programming language.  This document describes Idol in two parts.
  12. The first part presents Idol's object-oriented programming concepts
  13. as an integral tool with which a programmer maps a good program
  14. design into a good implementation.  As such, it serves as
  15. of "user's guide" for Idol's extensions to Icon.  Idol's
  16. object-oriented programming facilities are viewed within the
  17. broader framework of structured programming and modular design
  18. in general.  Idol's precise syntax and semantics are detailed in the
  19. second part, "An Icon-Derived Object Language", which serves as a
  20. reference manual.
  21.  
  22.  
  23.  
  24.  
  25.  
  26.              Object-Oriented Programming After a Fashion
  27.  
  28. Object-oriented programming means different things to different people.
  29. In Idol, object-oriented programming centers around encapsulation,
  30. inheritance, and polymorphism.  These key ideas are shared by most
  31. object-oriented languages as well as many languages that are not
  32. considered object-oriented.  This paper introduces these ideas and
  33. illustrates their use in actual code.  Idol is relevant in this
  34. discussion because programming concepts are more than mental
  35. exercises; they are mathematical notations by which programmers share
  36. their knowledge.
  37.  
  38. Object-oriented programming can be done in Smalltalk, C++, or
  39. assembler language for that matter, but this does not mean these
  40. programming notations are equally desirable.  Assembler languages
  41. are not portable.  For most programmers, Smalltalk uses an alien
  42. notation; Smalltalk programs also share the flaw that they do not
  43. work well in environments such as UNIX and DOS that consist of
  44. interacting programs written in many languages.  C++ has neither of
  45. these flaws, but the same low-level machine-oriented character
  46. that makes it efficient also makes C++ less than ideal as an
  47. algorithmic notation usable by nonexperts.
  48.  
  49. Idol owes most of its desirable traits to its foundation, the Icon
  50. programming language, developed at the University of Arizona
  51. [Griswold83].  In fact, Idol presents objects simply as a tool
  52. to aid in the writing of Icon programs. Idol integrates a concise,
  53. robust notation for object-oriented programming into a language
  54. considerably more advanced than C or Pascal.  Icon already uses a
  55. powerful notation for expressing a general class of algorithms. The
  56. purpose of Idol is to enhance that notation, not to get in the way.
  57.  
  58.  
  59.                              Key Concepts
  60.  
  61. This section describes the general concepts that Idol supplies
  62. to authors of large Icon programs.  The following section provides
  63. programming examples that employ these tools.  The reader is
  64. encouraged to refer back to this section when clarification in
  65. the examples section is needed.
  66.  
  67. The single overriding reason for object-oriented programming
  68. is the large program.  Simple programs can be easily written in
  69. any notation.  Somewhere between the 1,000-line mark and the
  70. 10,000-line mark most programmers can no longer keep track of their
  71. entire program at once.  By using a very high-level programming language,
  72. less lines of code are required; a programmer can write perhaps ten
  73. times as large a program and still be able to keep track of things.
  74. As programmers are required to write larger and larger programs,
  75. the benefit provided by very-high level languages does not keep up
  76. with program complexity.  This obstacle has been labelled the
  77. "software crisis", and object-oriented programming addresses this
  78. crisis.  In short, the goals of object-oriented programming are to
  79. reduce the amount of coding required to write very large programs and
  80. to allow code to be understood independently of the context of the
  81. surrounding program.  The techniques employed to achieve these goals
  82. are discussed below.
  83.  
  84.  
  85.                             Encapsulation
  86.  
  87. The primary concept advocated by object-oriented programming is the
  88. principle of encapsulation.  Encapsulation is the isolation, in the
  89. source code that a programmer writes, of a data representation and the code
  90. that manipulates the data representation.  In some sense, encapsulation
  91. is an assertion that no other routines in the program have "side-effects"
  92. with respect to the data structure in question.  It is easier to reason
  93. about encapsulated data because all of the source code that could affect
  94. that data is immediately present with its definition.
  95.  
  96. Encapsulation does for data structures what the procedure does for
  97. algorithms: it draws a line of demarcation in the program text, the
  98. outside of which is (or can be, or ought to be) irrelevant to the inside.
  99. We call an encapsulated data structure an object. Just as a set of
  100. named variables called parameters comprise the only interface between a
  101. procedure and the code that uses it, a set of named procedures called
  102. methods comprise the only interface between an object and the code that
  103. uses it.
  104.  
  105. This textual definition of encapsulation as a property of program
  106. source code accounts for the fact that good programmers can write
  107. encapsulated data structures in any language.  The problem is not
  108. capability, but verification.  In order to verify encapsulation some
  109. object-oriented languages, like C++, define an elaborate mechanism by
  110. which a programmer can govern the visibility of each data structure.
  111. Like Smalltalk, Idol instead attempts to simplify verification by
  112. preventing violations of encapsulation entirely.
  113.  
  114.  
  115.                              Inheritance
  116.  
  117. In large programs, the same or nearly the same data structures are
  118. used over and over again for a myriad of different purposes.  Similarly,
  119. variations on the same algorithms are employed by structure after
  120. structure.  In order to minimize redundancy, techniques are needed to
  121. support code sharing for both data structures and algorithms.
  122. Code is shared by related data structures by a programming concept
  123. called inheritance.
  124.  
  125. The basic premise of inheritance is simple: if I need to write code
  126. for a new data structure which is similar to one that's already
  127. written, I can specify the new structure by giving the differences
  128. between it and the old structure, instead of copying and then modifying
  129. the old structure's code.  Obviously there are times when the
  130. inheritance mechanism is not useful: if the two data structures are
  131. more different than they are similar, or if they are simple enough
  132. that inheritance would only confuse things, for example.
  133.  
  134. Inheritance addresses a variety of common programming problems found
  135. at different conceptual levels.  The most obvious software engineering
  136. problem it solves might be termed enhancement.  During the
  137. development of a program, its data structures may require extension
  138. via new state variables or new operations or both; inheritance is
  139. especially useful when both the original structure and the extension
  140. are used by the application.  Inheritance also supports
  141. simplification, or the reduction of a data structure's state variables
  142. or operations.  Simplification is analogous to argument culling after
  143. the fashion of the lambda calculus; it captures a logical relation
  144. between structures rather than a common situation in software
  145. development.  In general, inheritance may be used in source code to
  146. describe any sort of relational hyponymy, or special-casing; in Idol
  147. the collection of all inheritance relations defines a directed (not
  148. necessarily acyclic) graph.
  149.  
  150.  
  151.                              Polymorphism
  152.  
  153. From the perspective of the writer of related data structures,
  154. inheritance provides a convenient method for code sharing, but
  155. what about the code that uses objects?  Since objects are
  156. encapsulated, that code is not dependent upon the internals of
  157. the object at all, and it makes no difference to the client code
  158. whether the object in questions belongs to the original class or the
  159. inheriting class.
  160.  
  161. In fact, we can make a stronger statement.  Due to encapsulation,
  162. two different executions of some code that uses objects to implement
  163. a particular algorithm may operate on different objects that are
  164. not related by inheritance at all.  Such code may effectively
  165. be shared by any objects that happen to implement the operations
  166. that the code invokes.  This facility is called polymorphism, and
  167. such algorithms are called generic.  This feature is found in
  168. non-object oriented languages; in object-oriented languages it is
  169. a natural extension of encapsulation.
  170.  
  171.  
  172.                           Object Programming
  173.  
  174. The concepts introduced above are used in many programming languages
  175. in one form or another.  The following text presents these concepts
  176. in the context of actual Idol code.  This serves a dual purpose:
  177. it should clarify the object model adopted by Idol as well as
  178. provide an initial impression of these concepts' utility in coding.
  179. In order to motivate the constructs provided by Idol, our example
  180. begins by contrasting conventional Icon code with Idol code which
  181. implements the same behavior.  The semantics of the Idol code given
  182. here is defined by the Idol reference manual, included later in this
  183. document in the section entitled, "An Icon-Derived Object Language".
  184.  
  185.                             Before Objects
  186.  
  187. In order to place Idol objects in their proper context, the first
  188. example is taken from from regular Icon.  Suppose I am writing some
  189. text-processing application such as a text editor.  Such applications
  190. need to be able to process Icon structures holding the contents of
  191. various text files.  I might begin with a simple structure like the
  192. following:
  193.  
  194. record buffer(filename,text,index)
  195.  
  196. where filename is a string, text is a list of strings
  197. corresponding to lines in the file, and index is a marker for
  198. the current line at which the buffer is being processed.  Icon record
  199. declarations are global; in principle, if the above declaration needs
  200. to be changed, the entire program must be rechecked.  A devotee of
  201. structured programming would no doubt write Icon procedures to read
  202. the buffer in from a file, write it out to a file, examine, insert
  203. and delete individual lines, etc.  These procedures, along with the
  204. record declaration given above, can be kept in a separate source file
  205. (buffer.icn) and understood independently of the program(s) in
  206. which they are used.  Here is one such procedure:
  207.  
  208.  
  209. # read a buffer in from a file
  210. procedure read_buffer(b)
  211.   f := open(b.filename) | fail
  212.   b.text := [ ]
  213.   b.position := 1
  214.   every put(b.text,!f)
  215.   close(f)
  216.   return b
  217. end
  218.  
  219. There is nothing wrong with this example; in fact its similarity to the
  220. object-oriented example that follows demonstrates that a good, modular
  221. design is the primary effect encouraged by object-oriented programming.
  222. Using a separate source file to contain a record type and those
  223. procedures which operate on that type allows an Icon programmer to
  224. maintain a voluntary encapsulation of that type.
  225.  
  226.                             After Objects
  227.  
  228. Here is the same buffer abstraction coded in Idol.  This example
  229. lays the groundwork for some more substantial techniques to follow.
  230.  
  231. class buffer(public filename,text,index)
  232.   # read a buffer in from a file
  233.   method read()
  234.     f := open(self.filename) | fail
  235.     self$erase()
  236.     every put(self.text,!f)
  237.     close(f)
  238.     return
  239.   end
  240.   # write a buffer out to a file
  241.   method write()
  242.     f := open(self.filename,"w") | fail
  243.     every write(f,!self.text)
  244.     close(f)
  245.   end
  246.   # insert a line at the current index
  247.   method insert(s)
  248.     if self.index = 1 then {
  249.       push(self.text,s)
  250.     } else if self.index > *self.text then {
  251.       put(self.text,s)
  252.     } else {
  253.       self.text := self.text[1:self.index]|||[s]|||self.text[self.index:0]
  254.     }
  255.     self.index +:= 1
  256.     return
  257.   end
  258.   # delete a line at the current index
  259.   method delete()
  260.     if self.index > *self.text then fail
  261.     rv := self.text[self.index]
  262.     if self.index=1 then pull(self.text)
  263.     else if self.index = *self.text then pop(self.text)
  264.     else self.text := self.text[1:self.index]|||self.text[self.index+1:0]
  265.     return rv
  266.   end
  267.   # move the current index to an arbitrary line
  268.   method goto(l)
  269.     if (0 <= l) & (l <= self.index+1) then return self.index := l
  270.   end
  271.   # return the current line and advance the current index
  272.   method forward()
  273.     if self.index > *self.text then fail
  274.     rv := self.text[self.index]
  275.     self.index +:= 1
  276.     return rv
  277.   end
  278.   method erase()
  279.     self.text     := [ ]
  280.     self.index    := 1
  281.   end
  282. initially
  283.   if \ (self.filename) then {
  284.     if not self$read() then self$erase()
  285.   } else {
  286.     self.filename := "*scratch*"
  287.     self$erase()
  288.   }
  289. end
  290.  
  291.  
  292. This first example is not complex enough to illustrate the full
  293. object-oriented style, but its a start.  Pertaining to the
  294. general concepts introduced above, we can make the following
  295. initial observations:
  296.  
  297. Polymorphism. A separate name space for each class's methods
  298. makes for shorter names.  The same method name can be used in each
  299. class that implements a given operation.  This notation is more
  300. concise than is possible with standard Icon procedures.  More
  301. importantly it allows algorithms to operate correctly upon objects of
  302. any class which implements the operations required by the algorithm.
  303. Constructors.  A section of code is executed automatically when
  304. the constructor is called, allowing initialization of fields to values
  305. other than &null.  Of course, this could be simulated in Icon
  306. by writing a procedure that had the same effect; the value of the
  307. constructor is that it is automatic; the programmer is freed from the
  308. responsibility of remembering to call this code everywhere objects are
  309. created in the client program(s).  This tighter coupling of memory
  310. allocation and its corresponding initialization removes one more
  311. source of program errors, especially on multiprogrammer projects.
  312.  
  313.  
  314. These two observations share a common theme: the net effect is that
  315. each piece of data is made responsible for its own behavior in the
  316. system. Although this first example dealt with simple line-oriented
  317. text files, the same methodology applies to more abstract entities
  318. such as the components of a compiler's grammar (This example
  319. is taken from the Idol translator itself, which provides another
  320. extended example of polymorphism and inheritance.).
  321.  
  322. Idol's code sharing facilities are illustrated if we extend the above
  323. example.  Suppose the application is more than just a text editor---
  324. it includes word-associative databases such as a dictionary,
  325. bibliography, spell-checker, thesaurus, etc.  These various databases
  326. can be represented internally using Icon tables.  The table entries
  327. for the databases vary, but the databases all use string keyword
  328. lookup.  As external data, the databases can be stored in text files,
  329. one entry per line, with the keyword at the beginning.  The format
  330. of the rest of the line varies from database to database.
  331.  
  332. Although all these types of data are different, the code used to
  333. read the data files can be shared, as well as the initial construction
  334. of the tables.  In fact, since we are storing our data one entry per
  335. line in text files, we can use the code already written for buffers
  336. to do the file i/o itself.
  337.  
  338.  
  339. class buftable : buffer()
  340.   method read()
  341.     self$buffer.read()
  342.     tmp := table()
  343.     every line := !self.text do
  344.       line ? { tmp[tab(many(&letters))] := line | fail }
  345.     self.text := tmp
  346.     return
  347.   end
  348.   method lookup(s)
  349.     return self.text[s]
  350.   end
  351. end
  352.  
  353.  
  354. This concise example shows how little must be written to achieve
  355. data structures with vastly different behavioral characteristics,
  356. by building on code that is already written.  The superclass
  357. read() operation is one important step of the subclass
  358. read() operation; this technique is common enough to have a
  359. name: it is called method combination in the literature. It
  360. allows one to view the subclass as a transformation of the
  361. superclass.  The buftable class is given in its entirety, but
  362. our code sharing example is not complete: what about the data
  363. structures required to support the databases themselves?  They are all
  364. variants of the buftable class, and a set of possible
  365. implementations is given below.  Note that the formats presented are
  366. designed to illustrate code sharing; clearly, an actual application
  367. might make different choices.
  368.  
  369.                             Bibliographies
  370.  
  371. Bibliographies might consist of a keyword followed by an uninterpreted
  372. string of information.  This imposes no additional structure on the
  373. data beyond that imposed by the buftable class.  An example
  374. keyword would be Jeffery90.
  375.  
  376.  
  377. class bibliography : buftable()
  378. end
  379.  
  380.  
  381.  
  382.                             Spell-checkers
  383.  
  384. The database for a spell-checker is presumably just a list of words,
  385. one per line; the minimal structure required by the buftable
  386. class given above.  Some classes exist to introduce new terminology
  387. rather than define a new data structure.  In this case we introduce
  388. a lookup operation which may fail, for use in tests.  In addition,
  389. since many spell-checking systems allow user definable dictionaries
  390. in addition to their central database, we allow spellChecker
  391. objects to chain together for the purpose of looking up words.
  392.  
  393.  
  394. class spellChecker : buftable(parentSpellChecker)
  395.   method spell(s)
  396.     return \ (self.text[s]) | (\ (self.parentSpellChecker))$spell(s)
  397.   end
  398. end
  399.  
  400.  
  401.  
  402.                              Dictionaries
  403.  
  404. Dictionaries are slightly more involved.  Each entry might consist of a
  405. part of speech, an etymology, and an arbitrary string of uninterpreted
  406. text comprising a definition for that entry, separated by semicolons.
  407. Since each such entry is itself a structure, a sensible decomposition
  408. of the dictionary structure consists of two classes: one that manages
  409. the table and external file i/o, and one that handles the manipulation
  410. of dictionary entries, including their decoding and encoding as
  411. strings.
  412.  
  413.  
  414. class dictionaryentry(word,pos,etymology,definition)
  415.   method decode(s) # decode a dictionary entry into its components
  416.     s ? {
  417.       self.word       := tab(upto(';'))
  418.       move(1)
  419.       self.pos        := tab(upto(';'))
  420.       move(1)
  421.       self.etymology  := tab(upto(';'))
  422.       move(1)
  423.       self.definition := tab(0)
  424.     }
  425.   end
  426.   method encode()  # encode a dictionary entry into a string
  427.     return self.word||";"||self.pos||";"||self.etymology||";"||self.definition
  428.   end
  429. initially
  430.   if /self.pos then {
  431.     # constructor was called with a single string argument
  432.     self$decode(self.word)
  433.   }
  434. end
  435.  
  436. class dictionary : buftable()
  437.   method read()
  438.     self$buffer.read()
  439.     tmp := table()
  440.     every line := !self.text do
  441.       line ? { tmp[tab(many(&letters))] := dictionaryentry(line) | fail }
  442.     self.text := tmp
  443.   end
  444.   method write()
  445.     f := open(b.filename,"w") | fail
  446.     every write(f,(!self.text)$encode())
  447.     close(f)
  448.   end
  449. end
  450.  
  451.  
  452.                                Thesauri
  453.  
  454. Although an oversimplification, one might conceive of a thesauri as a
  455. list of entries, each of which consists of a comma-separated list of
  456. synonyms followed by a comma-separated list of antonyms, with a
  457. semicolon separating the two lists.  Since the code for such a
  458. structure is nearly identical to that given for dictionaries above,
  459. we omit it here (but one might reasonably capture a generalization
  460. regarding entries organized as fields separated by semicolons).
  461.  
  462.  
  463.                Objects and Icon Programming Techniques
  464.  
  465. In examining any addition to a language as large as Icon, a
  466. significant question is how that addition relates to the rest of the
  467. language. In particular, how does object-oriented programming fit into
  468. the suite of advanced techniques used regularly by Icon programmers?
  469. Previous sections of this document expound objects as an
  470. organizational tool, analogous but more effective than the use of
  471. separate compilation to achieve program modularity.  Object-oriented
  472. programming goes considerably beyond that viewpoint.
  473.  
  474. Whether viewed dynamically or statically, the primary effect achieved
  475. by object-oriented programming is the subdivision of program data in
  476. parallel with the code.  Icon already provides a variety of tools that
  477. achieve related effects:
  478.  
  479. Local and Static Variables in Icon procedures are the simplest
  480. imaginable parallel association of data and code.  We do not discuss
  481. them further, although they are by no means insignificant.
  482. Records allow a simple form of user-defined types. They provide
  483. a useful abstraction, but keeping records associated with the right
  484. pieces of code is still the job of the programmer.
  485. String Scanning creates scanning environments.  These are very
  486. useful, but not very general: not all problems can be cast as
  487. string operations.
  488. Co-expressions save a program state for later evaluation.  This
  489. powerful facility has a sweeping range of uses, but unfortunately it
  490. is a relatively expensive mechanism that is frequently misused to
  491. achieve a simple effect.
  492.  
  493.  
  494. Objects and classes, if they are successful, allow a significant
  495. generalization of the techniques developed around the above
  496. language mechanisms.  Objects do not replace these language
  497. mechanisms, but in many cases presented below they provide an
  498. attractive alternative means of achieving similar effects.
  499.  
  500.                          Objects and records
  501.  
  502. Objects are simply records whose field accesses are voluntarily
  503. limited to a certain set of procedures.
  504.  
  505.                   Objects and scanning environments
  506.  
  507. String scanning in Icon is another example of associating a piece of
  508. data with the code that operates on it.  In an Icon scanning
  509. expression of the form e1 ? e2, the result of evaluating
  510. e1 is used implicitly in e2 via a variety of scanning
  511. functions.  In effect, the scanning operation defines a scope in which
  512. state variables &subject and &pos are redefined.
  513. [Walker86] proposes an extension to Icon allowing
  514. programmer-defined scanning environments. The extension involves a new
  515. record data type augmented by sections of code to be executed upon
  516. entry, resumption, and exit of the scanning environment.  The Icon
  517. scanning operator was modified to take advantage of the new facility
  518. when its first argument was of the new environment data type.
  519.  
  520. While objects cannot emulate Icon string scanning syntactically, they
  521. generalize the concept of the programmer-defined scanning environment.
  522. Classes in the Idol standard library include a wide variety of
  523. scanning environments in addition to conventional strings.  The
  524. variation is not limited to the type of data scanned; it also includes
  525. the form and function of the scanning operations.  The form of
  526. scanning operations available are defined by the state variables they
  527. access; in the case of Icon's built-in string scanning, a single
  528. string and a single integer index into that string.
  529.  
  530. There is no reason that a scanning environment cannot maintain a more
  531. complex state, such as an input string, an output string, and a pair
  532. of indices and directions for each string.  Rather than illustrate
  533. the use of objects to construct scanning environments with such an
  534. abstract model, a concrete example is presented below.
  535.  
  536.                             List scanning
  537.  
  538. List scanning is a straightforward adaptation of string scanning to
  539. the list data type.  It consists of a library class named
  540. ListScan that implements the basic scanning operations, and
  541. various user classes that include the scanning expressions.  This
  542. format is required due to Idol's inability to redefine the semantics
  543. of the ? operator or to emulate its syntax in any reasonable
  544. way.  The state maintained during a list scan consists of
  545. Subject and Pos,  analogous to &subject and
  546. &pos, respectively.
  547.  
  548. ListScan defines analogies to the basic scanning functions of
  549. Icon, e.g. tab, upto, many, any, etc.  These
  550. functions are used in methods  of a ListScan client class, which
  551. in turn defines itself as a subclass of ListScan.  A client such as:
  552.  
  553. class PreNum : ListScan()
  554.   method scan()
  555.     mypos := self.Pos
  556.     suspend self$tab(self$upto(numeric))
  557.     self.Pos := mypos
  558.   end
  559. end
  560.  
  561. may be used in an expression such as
  562.  
  563. (PreNum(["Tucson", "Pima", 15.0, [ ], "3"]))$scan()
  564.  
  565. producing the result ["Tucson", "Pima"].  The conventional Icon
  566. string scanning analogy would be: "abc123" ? tab(upto(&digits)),
  567. which produces the result "abc".  Note that ListScan
  568. methods frequently take list-element predicates as arguments where
  569. their string scanning counterparts take csets.  In the above example,
  570. the predicate numeric supplied to upto is an Icon
  571. function, but predicates may also be arbitrary user-defined procedures.
  572.  
  573. The part of the Idol library ListScan class required to
  574. understand the previous example is presented below.  This code is
  575. representative of user-defined scanning classes allowing pattern
  576. matching over arbitrary data structures in Idol.  Although
  577. user-defined scanning is more general than Icon's built-in scanning
  578. facilities, the scanning methods given below are always
  579. activated in the context of a specific environment.  Icon string
  580. scanning functions can be supplied an explicit environment using
  581. additional arguments to the function.
  582.  
  583.  
  584. class ListScan(Subject,Pos)
  585.   method tab(i)
  586.     if i<0 then i := *self.Subject+1-i
  587.     if i<0 | i>*self.Subject+1 then fail
  588.     origPos := self.Pos
  589.     self.Pos := i
  590.     suspend self.Subject[origPos:i]
  591.     self.Pos := origPos
  592.   end
  593.   method upto(predicate)
  594.     origPos := self.Pos
  595.     every i := self.Pos to *(self.Subject) do {
  596.       if predicate(self.Subject[i]) then suspend i
  597.     }
  598.     self.Pos := origPos
  599.   end
  600. initially
  601.   /(self.Subject) := [ ]
  602.   /(self.Pos) := 1
  603. end
  604.  
  605.  
  606.  
  607.                       Objects and co-expressions
  608.  
  609. Objects cannot come close to providing the power of co-expressions,
  610. but they do provide a more efficient means of achieving well-known
  611. computations such as parallel expression evaluation that have been
  612. promoted as uses for co-expressions.  In particular, a co-expression
  613. is able to capture implicitly the state of a generator for later
  614. evaluation; the programmer is saved the trouble of explicitly coding
  615. what can be internally and automatically performed by Icon's
  616. expression mechanism.  While objects cannot capture a generator state
  617. implicitly, the use of library objects mitigates the cost of
  618. explicitly encoding the computation to be performed, as an
  619. alternative to the use of co-expressions.  The use of objects also is
  620. a significant alternative for implementations of Icon in which
  621. co-expressions are not available or memory is limited.
  622.  
  623.                          Parallel evaluation
  624.  
  625. In [Griswold87], co-expressions are used to obtain the results
  626. from several generators in parallel:
  627.  
  628. decimal   := create(0 to 255)
  629. hex       := create(!"0123456789ABCDEF" || !"0123456789ABCDEF")
  630. octal     := create((0 to 3) || (0 to 7) || (0 to 7))
  631. character := create(image(!&cset))
  632. while write(right(@decimal,3)," ",@hex," ",@octal," ",@character)
  633.  
  634.  
  635. For the Idol programmer, one alternative to using co-expressions would
  636. be to link in the following code from the Idol standard library:
  637.  
  638. procedure sequence(bounds[ ])
  639.   return Sequence(bounds)
  640. end
  641.  
  642. class Sequence(bounds,indices)
  643.   method max(i)
  644.     elem := self.bounds[i]
  645.     return (type(elem)== "integer",elem) | *elem-1
  646.   end
  647.   method elem(i)
  648.     elem := self.bounds[i]
  649.     return (type(elem)== "integer",self.indices[i]) | elem[self.indices[i]+1]
  650.   end
  651.   method activate()
  652.     top := *(self.indices)
  653.     if self.indices[1] > self$max(1) then fail
  654.     s := ""
  655.     every i := 1 to top do {
  656.       s ||:= self$elem(i)
  657.     }
  658.     repeat {
  659.        self.indices[top] +:= 1
  660.        if top=1 | (self.indices[top] <= self$max(top)) then break
  661.        self.indices[top] := 0
  662.        top -:= 1
  663.     }
  664.     return s
  665.   end
  666. initially
  667.   / (self.indices) := list(*self.bounds,0)
  668. end
  669.  
  670.  
  671. On the one hand, the above library code is neither terse nor general
  672. compared with co-expressions. This class does, however, allow the
  673. parallel evaluation problem described previously to be coded as:
  674.  
  675. decimal   := sequence(255)
  676. hex       := sequence("0123456789ABCDEF","0123456789ABCDEF")
  677. octal     := sequence(3,7,7)
  678. character := sequence(string(&cset))
  679. while write(right($@decimal,3)," ",$@hex," ",$@octal," ",image($@character))
  680.  
  681.  
  682. $@ is the unary Idol meta-operator that invokes the
  683. activate() operation. Since the sequence class is already
  684. written and available, its use is an attractive alternative to
  685. co-expressions in many settings.  For example, a general class of
  686. label generators (another use of co-expressions cited in
  687. [Griswold87]) is defined by the following library class:
  688.  
  689. class labelgen : Sequence(prefix,postfix)
  690.   method activate()
  691.     return self.prefix||self$Sequence.activate()||self.postfix
  692.   end
  693. initially
  694.   /(self.prefix) := ""
  695.   /(self.postfix) := ""
  696.   /(self.bounds)  := [50000]
  697. end
  698.  
  699. After creation of a label generator object (e.g.
  700. label := labelgen("L",":")), each resulting label is obtained
  701. via $@label. The sequence defined by this example is
  702.  
  703.         L0:
  704.         L1:
  705.         ...
  706.         L50000:
  707.  
  708.  
  709.                               Conclusion
  710.  
  711. Idol presents object programming as a collection of tools to reduce
  712. the complexity of large Icon programs.  These tools are encapsulation,
  713. inheritance, and polymorphism.  Since a primary goal of Idol is to
  714. promote code sharing and reuse, a variety of specific programming
  715. problems have elegant solutions available in the Idol class library.
  716.  
  717.  
  718.                    An Icon-Derived Object Language
  719.  
  720. This section serves as the language reference manual for Idol.  Idol
  721. is a preprocessor for Icon which implements a means of associating a
  722. piece of data with the procedures which manipulate it.  The primary
  723. benefits to the programmer are thus organizational.  The Icon
  724. programmer may view Idol as providing an augmented record type in
  725. which field accesses are made not directly on the records' fields, but
  726. rather through a set of procedures associated with the type.
  727.  
  728.  
  729.                                Classes
  730.  
  731. Since Idol implements ideas found commonly in object-oriented
  732. programming languages, its terminology is taken from that domain.  The
  733. augmented record type is called a "class".  The syntax of a class is:
  734.  
  735.  
  736. class foo(field1,field2,field3,...)
  737.    # procedures to access
  738.    # class foo objects
  739.  
  740. [code to initialize class foo objects]
  741. end
  742.  
  743.  
  744. In order to emphasize the difference between ordinary Icon procedures
  745. and the procedures which manipulate class objects, these procedures
  746. are called "methods" (the term is again borrowed from the
  747. object-oriented community).  Nevertheless, the syntax of a method is
  748. that of a procedure:
  749.  
  750.  
  751. method bar(param1,param2,param3,...)
  752.  
  753.    # Icon code which may access
  754.    # fields of a class foo object
  755. end
  756.  
  757.  
  758. Since execution of a class method is always associated with a given
  759. object of that class, the method has access to an implicit variable
  760. called self which is a record containing fields whose names are
  761. those given in the class declaration.  References to the self variable
  762. look just like normal record references; they use the dot (.)
  763. operator.  In addition to methods, classes may also contain regular
  764. Icon procedure, global, and record declarations; such declarations
  765. have the standard semantics and exist in the global Icon name space.
  766.  
  767.  
  768.                                Objects
  769.  
  770. Like records, instances of a class type are created with a constructor
  771. function whose name is that of the class.  Instances of a class are
  772. called objects, and their fields may be initialized explicitly in the
  773. constructor in exactly the same way as for records.  For example,
  774. after defining a class foo(x,y) one may write:
  775.  
  776.  
  777. procedure main()
  778.  
  779.   f := foo(1,2)
  780. end
  781.  
  782.  
  783. The fields of an object need not be initialized by the class
  784. constructor.  For many objects it is more logical to initialize their
  785. fields to some standard value.  In this case, the class declaration
  786. may include an "initially" section after its methods are defined and
  787. before its end.
  788.  
  789. This section begins with a line containing the word "initially" and
  790. then contains lines which are executed whenever an object of that
  791. class is constructed.  These lines may reference and assign to the
  792. class fields as if they were normal record fields for the object being
  793. constructed.  The "record" being constructed is named self;
  794. more on self later.
  795.  
  796. For example, suppose one wished to implement an enhanced table type
  797. which permitted sequential access to elements in the order they were
  798. inserted into the table.  This can be implemented by a combination of
  799. a list and a table, both of which would initialized to the appropriate
  800. empty structure:
  801.  
  802.  
  803. class taque(l,t) # pronouned `taco'
  804.  
  805.   # methods to manipulate taques,
  806.   # e.g. insert, lookup, foreach...
  807.  
  808. initially
  809.   self.l := [ ]
  810.   self.t := table()
  811. end
  812.  
  813.  
  814. And in such a case one can create objects without including arguments
  815. to the class constructor:
  816.  
  817.  
  818. procedure main()
  819.  
  820.   mytaque := taque()
  821. end
  822.  
  823.  
  824. In the absence of an initially section, missing arguments to a
  825. constructor default to the null value.  Together with an initially
  826. section, the class declaration looks rather like a procedure that
  827. constructs objects of that class.  Note that one may write classes
  828. with some fields that are initialized explicitly by the constructor
  829. and other fields are initialized automatically in the initially
  830. section.  In this case one must either declare the automatically
  831. initialized fields after those that are initialized in the
  832. constructor, or insert &null in the positions of the
  833. automatically initialized fields in the constructor.
  834.  
  835.  
  836.  
  837.                           Object Invocation
  838.  
  839. Once one has created an object with a class constructor, one
  840. manipulates the object by invoking methods defined by its class.
  841. Since objects are both procedures and data, object invocation is
  842. similar to both a procedure call and a record access.  The dollar
  843. ($) operator invokes one of an object's methods.  It used
  844. similarly to the dot (.) operator used to access record fields.
  845. Using the taque example:
  846.  
  847.  
  848. procedure main()
  849.   mytaque := taque()
  850.   mytaque$insert("greetings","hello")
  851.   mytaque$insert(123)
  852.   every write(mytaque$foreach())
  853.   if \(mytaque$lookup("hello"))
  854.     then write(", world")
  855. end
  856.  
  857.  
  858. Note that direct access to an object's fields using the usual dot (.)
  859. operator is not possible outside of a method of the appropriate class.
  860. Attempts to reference mystack.l in procedure main() would result in
  861. a runtime error (invalid field name).  Within a class method, the
  862. implicit variable self allows access to the object's fields in
  863. the usual manner.  The taque insert method is thus:
  864.  
  865.  
  866.   method insert(x,key)
  867.     /key := x
  868.     put(self.l,x)
  869.     self.t[key] := x
  870.   end
  871.  
  872.  
  873. The self variable is both a record and an object.  It allows field
  874. access just like a record, as well as method invocation like any other
  875. object.  Thus class methods can use self to invoke other class methods
  876. without any special syntax.
  877.  
  878.  
  879.  
  880.                              Inheritance
  881.  
  882. In many cases, two classes of objects are very similar.  In
  883. particular, many classes can be thought of simply as enhancements of
  884. some class that has already been defined.  Enhancements might take the
  885. form of added fields, added methods, or both.  In other cases a class
  886. is just a special case of another class.  For example, if one had
  887. defined a class fraction(numerator, denominator), one might want to
  888. define a class inverses(denominator) whose behavior was identical to
  889. that of a fraction, but whose numerator was always 1.
  890.  
  891. Idol supports both of these ideas with the concept of inheritance.
  892. When the definition of a class is best expressed in terms of the
  893. definition of another class or classes, we call that class a subclass
  894. of the other classes.  This corresponds to the logical relation of
  895. hyponymy. It means an object of the subclass can be manipulated just
  896. as if it were an object of one of its defining classes.  In practical
  897. terms it means that similar objects can share the code that
  898. manipulates their fields. The syntax of a subclass is
  899.  
  900.  
  901. class foo : superclasses (fields...)
  902.  
  903. # methods
  904. [optional initially section]
  905. end
  906.  
  907.  
  908.  
  909.                          Multiple Inheritance
  910.  
  911. There are times when a new class might best be described as a
  912. combination of two or more classes.  Idol classes may have more than
  913. one superclass, separated by colons in the class declaration.  This is
  914. called multiple inheritance.
  915.  
  916. Subclasses define a record type consisting of all the fieldnames found
  917. in the class itself and in all its superclasses.  The subclass has
  918. associated methods consisting of those in its own body, those in the
  919. first superclass which were not defined in the subclass, those in the
  920. second superclass not defined in the subclass or the first superclass,
  921. and so on.  Fields are initialized either by the constructor or by the
  922. initially section of the first class of the class:superclass list in
  923. which the field is defined.  For example, to define a class of
  924. inverses in terms of a class fraction(numerator,denominator) one
  925. would write:
  926.  
  927.  
  928. class inverse : fraction (denominator)
  929. initially
  930.   self.numerator := 1
  931. end
  932.  
  933.  
  934. Objects of class inverse can be manipulated using all the methods
  935. defined in class fraction; the code is actually shared by both classes
  936. at runtime.
  937.  
  938. Viewing inheritance as the addition of fieldnames and methods of
  939. superclasses not already defined in the subclass is the opposite of
  940. the more traditional object-oriented view that a subclass starts with
  941. an instance of the superclass and augments or overrides portions of
  942. the definition with code in the subclass body.  Idol's viewpoint adds
  943. quite a bit of leverage, such as the ability to define classes which
  944. are subclasses of each other.  This feature is described further below.
  945.  
  946.  
  947.                     Invoking Superclass Operations
  948.  
  949. When a subclass defines a method of the same name as a method defined
  950. in the superclass, invocations on subclass objects always result in
  951. the subclass' version of the method.  This can be overridden by
  952. explicitly including the superclass name in the invocation:
  953.  
  954. object$superclass.method(parameters)
  955.  
  956. This facility allows the subclass method to do any additional work
  957. required for added fields before or after calling an appropriate
  958. superclass method to achieve inherited behavior.  The result is
  959. frequently a chain of inherited method invocations.
  960.  
  961.  
  962.  
  963.                             Public Fields
  964.  
  965.  
  966. As noted above, there is a strong correspondence between records and
  967. classes.  Both define new types which extend Icon's built in
  968. repertoire.  For simple jobs, records are slightly faster as well as
  969. more convenient: the user can directly read and write a record's
  970. fields by name.
  971.  
  972. Classes, on the other hand, promote the re-use of code and reduce the
  973. complexity required to understand or maintain large, involved
  974. structures.  They should be used especially when manipulating
  975. composite structures ontaining mixes of structures as elements, e.g.
  976. lists containing tables, sets, and lists in various positions.
  977.  
  978. Sometimes it would be really nice to access fields in an object
  979. directly, as with records.  An example from the Idol program itself is
  980. the name field associated with methods and classes---it is a
  981. string which is intended to be read outside the object.  One can
  982. always implement a method which returns (or assigns, for that matter)
  983. a field value, but this gets tedious.  Idol currently supports
  984. read-only access to fields via the public keyword.  If
  985. public precedes a fieldname in a class declaration, Idol
  986. automatically generates a method of the same name which dereferences
  987. and returns the field.  For example, the declaration
  988.  
  989. class sinner(pharisee,public publican)
  990.  
  991. generates code equivalent to the following class method in addition
  992. to any explicitly defined methods:
  993.  
  994.   method publican()
  995.     return .(self.publican)
  996.   end
  997.  
  998.  
  999. This feature, despite its utility and the best of intentions, makes it
  1000. possible to subvert object encapsulation: it should not be
  1001. used with fields whose values are structures, since the structure
  1002. could then be modified from the outside.  When invoked with the
  1003. -strict option, Idol generates code for public methods which
  1004. checks for a scalar type at runtime before returning the field.
  1005.  
  1006.  
  1007.  
  1008.                 Superclass Cycles and Type Equivalence
  1009.  
  1010. In many situations, there are several ways to represent the same
  1011. abstract type.  Two-dimensional points might be represented by
  1012. Cartesian coordinates x and y, or equivalently by radial coordinates
  1013. expressed as degree d and radian r.  If one were implementing classes
  1014. corresponding to these types there is no reason why one of them should
  1015. be considered a subclass of the other.  The types are truly
  1016. interchangeable and equivalent.
  1017.  
  1018. In Idol, expressing this
  1019. equivalence is simple and direct.  In defining classes Cartesian
  1020. and Radian we may declare them to be superclasses of each other:
  1021.  
  1022. class Cartesian : Radian (x,y)
  1023. # code which manipulates objects using cartesian coordinates
  1024. end
  1025.  
  1026. class Radian : Cartesian (d,r)
  1027. # code which manipulates objects using radian coordinates
  1028. end
  1029.  
  1030. These superclass declarations make the two types equivalent names for
  1031. the same type of object; after inheritance, instances of both classes
  1032. will have fields x,y,d, and r, and support the same set of operations.
  1033.  
  1034. Equivalent types each have their own constructor given by their class
  1035. name; although they export the same set of operations, the actual
  1036. procedures invoked by the different instances may be different.  For
  1037. example, if both classes define an implementation of a method
  1038. print, the method invoked by a given instance depends on
  1039. which constructor was used when the object was created.
  1040.  
  1041. If a class inherits any methods from one of its equivalent
  1042. classes, it is responsible for initializing the state of all
  1043. the fields used by those methods in its own constructor, and
  1044. maintaining the state of the inherited fields when its methods make
  1045. state changes to its own fields.  In the geometric example given
  1046. above, in order for class Radian to use any methods inherited
  1047. from class Cartesian, it must at least initialize x and y explicity
  1048. in its constructor from calculations on its d and r parameters.
  1049. In general, this added responsibility is minimized in those classes
  1050. which treat an object's state as a value rather than a structure.
  1051.  
  1052. The utility of equivalent types expressed by superclass cycles remains
  1053. to be seen.  At the least, they provide a convenient way to write
  1054. several alternative constructors for the same class of objects.
  1055. Perhaps more importantly, their presence in Idol causes us to question
  1056. the almost religious dogmatism that the superclass graph must always
  1057. be acyclic.
  1058.  
  1059.  
  1060.  
  1061.                               Miscellany
  1062.  
  1063. Idol supports some shorthand for convenient object invocation.  In
  1064. particular, if a class defines methods named size, foreach, random,
  1065. or activate, these methods can be invoked by a modified version of
  1066. the usual Icon operator:
  1067.  
  1068.  
  1069. $*x is equivalent to x$size()
  1070. $?x is equivalent to x$random()
  1071. $!x is equivalent to x$foreach()
  1072. $@x is equivalent to x$activate()
  1073.  
  1074.  
  1075. Other operators may be added to this list.  If x is an identifier
  1076. it may be used directly; if it is a more complex expression (such as a
  1077. function call) it should be parenthesized, e.g.
  1078. $*(complex_expression()).
  1079. Parentheses are also required in the case of invoking an object
  1080. returned from an invocation, e.g.
  1081.  
  1082.   (classes$lookup("theClass"))$name()
  1083.  
  1084. These requirements are artifacts of the first implementation and are
  1085. subject to change.
  1086.  
  1087. The Idol preprocessor is written in Idol and does not actually parse
  1088. the language it purports to implement.  In particular, the
  1089. preprocessor is line-oriented and class and method declarations, the
  1090. initially keyword, and the class and method end keyword need to be on
  1091. a line by themselves.  Similarly, both the object being invoked and
  1092. its method and parameters must be on the same line for invocations.
  1093.  
  1094. The Idol preprocessor reserves certain names for internal use.  In
  1095. particular, __state and __methods are not legal class
  1096. field names.  Similarly, the name idol_object is reserved in the
  1097. global name space, and may not be used as a global variable, procedure,
  1098. or record name. Finally, for each class foo amongst the user's
  1099. code, the names foo, foo___state, foo___methods,
  1100. foo__oprec are reserved, as are the names foo__bar
  1101. corresponding to each method bar in class foo. These
  1102. details are artifacts of the current implementation and are subject
  1103. to change.
  1104.  
  1105. Subclass constructors can be confusing, especially when multiple
  1106. inheritance brings in various fields from different superclasses.
  1107. One significant problem for users of the subclass is that the
  1108. parameters expected in the constructor may not be obvious if they
  1109. are inherited from a superclass.  On the other side of the spectrum,
  1110. superclasses which automatically initialize their fields can be
  1111. less than useful if the subclass might need to override the
  1112. default initialization value--the subclass must then explicitly
  1113. name the field in order to make its initially section have
  1114. precedence over the superclass.
  1115.  
  1116. The first of the two problems given above can be solved by naming
  1117. fields explicitly in a subclass when initialization by constructor.
  1118. This achieves clarity at the expense of changing the inheritance
  1119. behavior, since the subclass no longer inherits the superclass
  1120. automatic initialization for that field if there is one.  The latter
  1121. of the two problems can generally be solved by using the / operator
  1122. in automatic field initializations unless the initialization should
  1123. never be overridden.
  1124.  
  1125. While it is occasionally convenient to redeclare an inherited field
  1126. in a subclass, accidentally doing so and then using that field to store an
  1127. unrelated value would be disastrous.  Although Idol offers no proper
  1128. solution to this problem, the -strict option causes the generation
  1129. of warning messages for each redefined field name noting the relevant
  1130. sub- and superclasses.
  1131.  
  1132.  
  1133.  
  1134.                              Running Idol
  1135.  
  1136. Idol requires Version 7.5 or higher of Icon.  It runs best on UNIX
  1137. systems.  It has not been ported to all the various micros and
  1138. operating systems on which Icon 7.5 runs.  In particular, if your
  1139. version of Icon does not support the system() function, or your
  1140. machine does not have adequate memory available, Idol will not be
  1141. able to invoke icont to complete its translation and linking.
  1142. Since Idol is untested on many systems, you may have to make small
  1143. changes to the source code in order to port it to a new system.
  1144.  
  1145.                             Getting a Copy
  1146.  
  1147. Idol is in the public domain.  It is available on the Icon BBS and by
  1148. anonymous ftp from cs.arizona.edu.  Idol is also distributed with
  1149. the program library for Version 8 of Icon and is available by mail in
  1150. this way.  Interested parties may contact the author
  1151. (cjeffery@cs.arizona.edu):
  1152.  
  1153.  
  1154.          Department of Computer Science
  1155.          University of Arizona
  1156.          Tucson, AZ 85721
  1157.  
  1158.  
  1159.                      Creating an Idol executable
  1160.  
  1161. Idol is typically distributed in both Idol and Icon source forms.
  1162. Creating an Idol executable requires a running version of Icon and a
  1163. copy of idolboot.icn, the Icon source for Idol.  A second Icon
  1164. source file contains the operating-system dependent portion of Idol;
  1165. for example, unix.icn (see the Idol README file for the name of
  1166. your system file if you are not on a UNIX system; you may have to
  1167. write your own, but it is not difficult).  Using icont, compile
  1168. idolboot.icn and unix.icn into an executable file (named
  1169. idolboot, or  idolboot.icx). As a final step, rename this
  1170. executable to idol (or idol.icx).
  1171.  
  1172.  
  1173.                 Installing the Idol Library Mechanism
  1174.  
  1175. For each directory in which Idol source is kept, the Idol preprocessor
  1176. normally uses a subdirectory to store its generated code on systems
  1177. which support a hierarchical file system.  On systems without a
  1178. hierarchy, it stores generated code in the source directory.  Before
  1179. actually running Idol on any source files you should install the
  1180. Idol libraries.  This is done by invoking the command
  1181.  
  1182. idol -install
  1183.  
  1184. (some systems use "iconx idol -install").  Follow any
  1185. directions given at this point; on most systems installation is
  1186. entirely automatic.
  1187.  
  1188.  
  1189.                       Translating Idol Programs
  1190.  
  1191. The syntax for invoking idol is normally
  1192.  
  1193. idol file1[.iol] [files...]
  1194.  
  1195. (on some systems you may have to say "iconx idol" where it
  1196. says "idol" above).  The Idol translator creates a separate
  1197. Icon file for each class in the Idol source files you give it.  On
  1198. most systems it calls icont automatically to create ucode for these
  1199. files.  If the first file on the command line has any normal Icon code
  1200. in it (in addition to any class definitions it may contain), Idol
  1201. attempts to link it to any classes it may need and create an executable.
  1202.  
  1203. The file extension defaults to .iol.  Idol also accepts
  1204. extensions .icn, .u1, and .cl.  The first two refer
  1205. to Icon source or already translated code for which Idol generates
  1206. link statements in the main (initial) Idol source file.  Idol treats
  1207. arguments with the extension .cl as class names and generates
  1208. link statements for that class and its superclasses.
  1209.  
  1210.                               References
  1211.  
  1212.  
  1213.  
  1214. [Gris83]
  1215. Griswold, R.E. and Griswold, M.T.
  1216. The Icon Programming Language.
  1217. Prentice-Hall, Englewood Cliffs, New Jersey, 1983.
  1218.  
  1219. [Gris87]
  1220. Griswold, R.E.
  1221. Programming in Icon; Part I---Programming with
  1222.   Co-Expressions.
  1223. Technical Report 87-6, Department of Computer Science, University of
  1224.   Arizona, June 1987.
  1225.  
  1226. [Walk86]
  1227. Walker, K.
  1228. Dynamic Environments---A Generalization of Icon String
  1229.   Scanning.
  1230. Technical Report 86-7, Department of Computer Science, University of
  1231.   Arizona, March 1986.
  1232.  
  1233.  
  1234.